package test;

import com.alibaba.fastjson.JSON;

import java.io.*;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class SocketClient {

    private static final String FILE_PATH = "filePath";
    private static final String FILE_OPERATION = "operation";
    private static final String FILE_UPLOAD = "upload";
    private static final String FILE_DOWNLOAD = "download";

    /**
     * 上传文件
     *
     * @param ip
     * @param port
     * @param filePath
     * @return
     * @throws Exception
     */
    public static boolean uploadFile(String ip, int port, String filePath) {
        // 文件路径及文件名称
        // String filePath = map.get(FILE_PATH);
        if (filePath == null || filePath.length() == 0) {
            System.out.println("文件路径及文件名称不能为空");
            return false;
        }
        Map<String, String> map = new HashMap<>();
        // 操作为上传
        map.put(FILE_OPERATION,FILE_UPLOAD);


        File file  = new File(filePath);
        if (!file.exists()) {
            System.out.println("文件不存在");
            return false;
        }
        // 清理了windows盘符数据，否则服务端可能会报错
        if(filePath.contains(":")){
            String [] fileArray = filePath.split(":");
            filePath = fileArray[fileArray.length-1];
        }
        map.put(FILE_PATH,filePath);
        String fileJson = JSON.toJSONString(map);
        FileInputStream fis = null;
        Socket sock = null;
        DataOutputStream dos = null;
        String result = "";
        try {
            // 指定服务端地址和端口
            sock = new Socket(ip, port);
            // 60s超时
            //sock.setSoTimeout(60000);
            // 读取本地文件
            fis = new FileInputStream(file);
            dos = new DataOutputStream(sock.getOutputStream());
            //文件信息和长度
            dos.writeUTF(fileJson);
            dos.flush();
            dos.writeLong(file.length());
            dos.flush();
            //传输文件
            byte[] sendBytes = new byte[1024];
            int length = 0;
            while((length = fis.read(sendBytes, 0, sendBytes.length)) > 0){
                dos.write(sendBytes, 0, length);
                dos.flush();
            }
            fis.close();
            dos.close();
            System.out.println("文件上传完成");
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
                /** 关闭Socket*/
                if (sock != null) {
                    sock.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    public static boolean downLoadFile(String ip, int port, String filePath){

        if (filePath == null || filePath.length() == 0) {
            return false;
        }
        String downLoadFilePath = "";
        // 清理了windows盘符数据，否则服务端可能会报错
        if(filePath.contains(":")){
            String [] fileArray = filePath.split(":");
            downLoadFilePath = fileArray[fileArray.length-1];
        }else{
            downLoadFilePath = filePath;
        }
        Map<String, String> map = new HashMap<>();
        map.put(FILE_PATH, downLoadFilePath);
        // 操作为上传
        map.put(FILE_OPERATION,FILE_DOWNLOAD);
        String fileJson = JSON.toJSONString(map);

        File fi = new File(filePath);
        File pDir = new File(fi.getParent());
        if (!pDir.exists()) {
            pDir.mkdirs();
        }

        Socket sock = null;
        DataOutputStream fileOut = null;
        DataOutputStream dos = null;
        DataInputStream inputStream = null;
        try {
            // 指定服务端地址和端口
            sock = new Socket(ip, port);
            // 设置文件读取超时时间，设置100分钟在内网情况下，一般情况足够下载大文件了，超大文件只能去掉当前。
			//sock.setSoTimeout(6000000);
            // 定义socket输出流
            // 先发送文件名.让服务端知道
            dos = new DataOutputStream(sock.getOutputStream());
            // 发送下载文件信息和上传文件长度
            dos.writeUTF(fileJson);
            dos.flush();
            dos.writeLong(0);
            dos.flush();

            inputStream = new DataInputStream(new BufferedInputStream(sock.getInputStream()));

            byte[] buf = new byte[1024];
            fileOut = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(filePath)));
            // 下载文件名
            String fileName = inputStream.readUTF();
            // 读取文件长度
            long len = inputStream.readLong();

            // 服务端说已经接收文件名及其路径和操作信息
            while (true) {
                int read = 0;
                if (inputStream != null) {
                    read = inputStream.read(buf);
                }
                if (read == -1) {
                    break;
                }
                fileOut.write(buf, 0, read);
            }
            fileOut.flush();
            // 必须的,要告诉服务端该文件的数据已写完
            sock.shutdownOutput();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(inputStream != null) {
                    inputStream.close();
                }
                if(fileOut != null) {
                    fileOut.close();
                }
                if(dos != null) {
                    dos.close();
                }
                if(sock != null || !sock.isClosed()) {
                    sock.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    public static void main(String[] args) throws Exception {
        Map<String, String> map = new HashMap<>();
        // 访问操作
        map.put("filePath", "E:\\发票1.png");
        // 文件完整路径 , window注意去掉盘符
        String ip = "localhost";// 设置成服务器IP
        int port = 8821;//设置端口号
//        boolean result = SocketClient.uploadFile(ip, port, "E:\\实例\\发票1.png");
        boolean result = SocketClient.downLoadFile(ip, port, "E:\\实例\\发票1.png");

        System.out.println(result);
    }
}
